<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<div th:replace="~{commons/commons::head}"></div>

<body>
<div th:replace="~{commons/commons::topbar}"></div>

<div class="container-fluid">
    <div class="row">
        <div th:replace="~{commons/commons::siderbar(active='upload.html')}"></div>

        <main role="main" class="col-md-10 offset-md-2 pt-3 main">
            <div class="card">
                <div class="card-header py-1">
                    <div class="vul_header">
                        <span>文件操作 - 任意文件上传</span>
                        <span class="header_link">
                            <a class="btn btn-sm btn-primary"
                               href="#">漏洞案例</a>
                            <a class="btn btn-sm btn-primary"
                               href="#">wiki</a>
                        </span>
                    </div>
                </div>
                <div class="card-body">
                    <ul class="nav nav-tabs">
                        <li class="nav-item">
                            <a class="nav-link active" data-toggle="tab" href="#vulDescription">
                                漏洞描述</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" data-toggle="tab" href="#secureCoding"> 安全编码</a>
                        </li>
                    </ul>

                    <div class="tab-content">
                        <div class="tab-pane active" id="vulDescription">
                            <div class="alert alert-desc"><i class="lnr lnr-alarm"></i>
                                文件上传漏洞，是指攻击者通过上传恶意文件来获得对服务器的控制权的漏洞。<br>攻击者通常会利用Web应用程序的文件上传功能，将一个包含恶意代码的文件上传到服务器上。如果服务器没有正确地检查和限制上传的文件类型、大小、后缀名等信息，攻击者就可以上传一个包含恶意代码的文件，如php、jsp、asp等可执行脚本文件，然后通过访问上传的文件来执行恶意代码，从而获得对服务器的控制权。
                            </div>
                        </div>
                        <div class="tab-pane fade" id="secureCoding">
                            <div class="alert alert-desc">
                                <li>【必须】文件类型限制</li>
                                必须在服务器端采用白名单方式对上传或下载的文件类型、大小进行严格的限制。仅允许业务所需文件类型上传，避免上传.jsp、.jspx、.html、.exe等危险文件。

                                <li>【建议】其他</li>
                                对上传的文件回显相对路径或者不显示路径。
                                设置目录权限限制，禁止上传目录的执行权限。
                                建议使用OSS静态存储服务器来存储用户上传的文件。
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <div th:if="${message}">
                <span style="color:red" th:text="${message}"/>
            </div>
            <br>

            <div class="box-float">
                <div class="float1">
                    <h5><span class="lnr lnr-bug"> 漏洞代码 - 任意文件上传</span></h5>
                    <div class="alert alert-upload">
                        <form method="POST" th:action="@{/vulnapi/upload/uploadVul}" enctype="multipart/form-data">
                            <input type="file" name="file"/>
                            <input type="submit" class="btn btn-sm btn-danger" value="上传"/>
                        </form>
                    </div>
                    <textarea class="form-control" id="code1">
@PostMapping("/uploadVul")
public String uploadVul(@RequestParam("file") MultipartFile file) {
    try {
        byte[] bytes = file.getBytes();
        Path dir = Paths.get(UPLOADED_FOLDER);
        Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
        Files.write(path, bytes);
    } catch (Exception e) {
         return e.toString();
    }
    return "redirect:uploadStatus";
}
                    </textarea><br><br>

                    <h5><span class="lnr lnr-bug"> 漏洞代码 - 文件类型绕过</span></h5>
                    <div class="alert alert-upload">
                        <form method="POST" th:action="@{/vulnapi/upload/uploadVul2}" enctype="multipart/form-data">
                            <input type="file" name="file"/>
                            <input type="submit" class="btn btn-sm btn-danger" value="上传"/>
                        </form>
                    </div>

                    <textarea class="form-control" id="code3">
/**
 * 文件类型检测仅基于 Content-Type 头信息，可被绕过
 */
String contentType = file.getContentType();
if (!"image/jpeg".equals(contentType) && !"image/png".equals(contentType)) {
    redirectAttributes.addAttribute("error", "不允许上传该类型文件！");
    return "redirect:uploadStatus";
}
                    </textarea>
                </div>

                <div class="float2">
                    <h5><span class="lnr lnr-smile"> 安全代码 - 白名单后缀名</span></h5>
                    <div class="alert alert-upload">
                        <form method="POST" th:action="@{/vulnapi/upload/uploadSafe}" enctype="multipart/form-data">
                            <input type="file" name="file"/>
                            <input type="submit" class="btn btn-sm btn-success" value="上传"/>
                        </form>
                    </div>
                    <textarea class="form-control" id="code2">
private boolean isValidFileType(String fileName) {
    String[] allowedTypes = {"jpg", "jpeg", "png", "gif", "bmp", "ico"};
    String extension = StringUtils.getFilenameExtension(fileName);
    if (extension != null) {
        for (String allowedType : allowedTypes) {
            if (allowedType.equalsIgnoreCase(extension)) {
                return true;
            }
        }
    }
    return false;
}
                    </textarea><br><br>
                    <h5><span class="lnr lnr-bug"> 漏洞代码 - 前端校验绕过</span></h5>
                    <div class="alert alert-upload">
                        <form method="POST" th:action="@{/vulnapi/upload/uploadVul}" enctype="multipart/form-data">
                            <input type="file" name="file" accept=".jpg,.jpeg,.png" required/>
                            <input type="submit" class="btn btn-sm btn-danger" value="上传"/>
                        </form>
                    </div>

                    <textarea class="form-control" id="code4">
/**
 * 前端通过 accept 属性限制上传文件的后缀名，但仅依赖前端判断是不可靠的
 * 攻击者可以通过修改文件后缀名来绕过此限制，进一步的验证应在后端进行
 */
<form id="upload-form" method="POST" enctype="multipart/form-data">
    <input type="file" id="file" name="file" accept=".jpg,.jpeg,.png" required>
    <button type="submit">上传</button>
</form>
                    </textarea>
                </div>
            </div>
        </main>
    </div>
</div>

<!-- 引入script -->
<div th:replace="~{commons/commons::script}"></div>

</body>

</html>